package org.webball.player;

import java.util.Random;

import org.webball.base.abstracts.AbstractBall;
import org.webball.base.abstracts.AbstractPlayer;
import org.webball.tools.MKVector;
import java.math.*;

/**
 * <p>
 * Class represents attributes of player and operations he performs
 * extends AbstractPlayer
 * </p>
 * @author Dominik Kaminski
 *
 */
public class Player extends AbstractPlayer {

		/**
		 * current power value
		 */
       protected float fpower;
       /**
		 * current speed value
		 */
       protected float fspeed;

       /**
        * power chosen by user,
        * it doesn't change its value during gameplay,
        * fpower (which changes its value)
        * is being compared with chosen_power during gameplay
        */
       protected float chosen_power;
       
       /**
        * speed chosen by user,
        * it doesn't change its value during gameplay,
        * fspeed (which changes its value)
        * is being compared with chosen_speed during gameplay
        */
       protected float chosen_speed;
       
       /**
        * attack precision chosen by user,
        * it doesn't change its value during gameplay,
        * attack_precision (which changes its value)
        * is being compared with chosen_attack_precision during gameplay
        */
       protected int chosen_attack_precision;
       
       /**
        * pass precision chosen by user,
        * it doesn't change its value during gameplay,
        * pass_precision (which changes its value)
        * is being compared with chosen_pass_precision during gameplay
        */
       protected int chosen_pass_precision;
       
       /**
        * serve precision chosen by user,
        * it doesn't change its value during gameplay,
        * serve_precision (which changes its value)
        * is being compared with chosen_serve_precision during gameplay
        */
       protected int chosen_serve_precision;

        public Player() {
        	// default vaules
            size = 20;
            fpower = 0.8f;
            fspeed = 0.5f;
            this.setSpeed(7);
            this.setPower(7);
            chosen_attack_precision = 7;
            chosen_pass_precision = 7;
            chosen_serve_precision = 7;
            attack_precision = chosen_attack_precision;
            pass_precision = chosen_pass_precision;
            serve_precision = chosen_serve_precision;
       }
       protected float previous_condition = 101;
       protected MKVector movement;
      
       public float getPower() {
	   		return chosen_power;
	   	}
       
       /**
       *
       * @param ch_power (chosen power)
       */
      public void setPower(int ch_power){
          this.chosen_power = 0.5f + ch_power*0.03f;
          this.fpower = this.chosen_power;
      }

      public float getSpeed() {
	   		return chosen_speed;
	   	}
       
       /**
        *
        * @param ch_speed (chosen speed)
        */
       public void setSpeed(int ch_speed){
    	   this.chosen_speed = 0.5f + ch_speed*0.03f;
           this.fspeed = this.chosen_speed;
       }

       
       /**
        *
        * @return chosen attack precision
        */
       public int getAttackPrecision(){
               return chosen_attack_precision ;
       }

       /**
        *
        * @param ch_attack_precision (chosen attack precision)
        */
       public void setAttackPrecision(int ch_attack_precision){
               this.chosen_attack_precision = ch_attack_precision;
       }

       /**
        *
        * @return chosen pass precision
        */
       public int getPassPrecision(){
               return chosen_pass_precision ;
       }

       /**
        *
        * @param ch_pass_precision (chosen pass precision)
        */
       public void setPassPrecision(int ch_pass_precision){
               this.chosen_pass_precision = ch_pass_precision;
       }

       /**
        *
        * @return chosen serve precision
        */
       public int getServePrecision(){
               return chosen_serve_precision ;
       }

       /**
        *
        * @param ch_serve_precision (chosen serve precision)
        */
       public void setServePrecision(int ch_serve_precision){
               this.chosen_serve_precision = ch_serve_precision;
       }

       /**
        * method which performs action
        * @param ball to hit, precision_change
        */
       private void action(AbstractBall ball, int precision_changeX, int precision_changeY){
               if(getHitTarget() != null){
                       if(this.condition>0){
                               this.previous_condition = this.condition;
                               this.condition= this.condition-5;
                       }
                       MKVector temp_target = new MKVector();
                       Random rand = new Random();
                       int temp1 = rand.nextInt(4);
                       int temp2 = rand.nextInt(4);
                       temp_target.set((float) (this.getHitTarget().x + 
                    		   Math.pow(-1,Math.floor(((temp1-2)/2))-1)*precision_changeX*(10 - this.serve_precision)),
                    		   (float) (this.getHitTarget().y + 
                    		   Math.pow(-1,temp2)*precision_changeY*(10 - this.serve_precision)));
                       ball.setMovementTarget(temp_target);
                       this.update_skills();
               }
       }

       /**
        * method which serves
        * @param ball to hit
        */
       public void serve(AbstractBall ball){
               ball.setSpeed(this.fpower-0.05f);
               this.action(ball, 4, 4);
               if(this.fpower>0.4)
               this.fpower -= 0.1f;
       }

       /**
        * method which attacks
        * @param ball to hit
        */
       public void attack(AbstractBall ball){
               ball.setSpeed(this.fpower);
               this.action(ball, 4, 3);
               if(this.fpower>0.4)
               this.fpower -= 0.05f;
       }

       /**
        * method which passes ball
        * @param ball to hit
        */
       public void pass(AbstractBall ball){
               ball.setSpeed(this.fpower+0.1f);
               this.action(ball, 3, 2);
               if(this.fpower>0.4)
               this.fpower -= 0.05f;
       }

       /**
        * method which updates players skills:
        * power, attack_precision,
        * pass_precision and speed
        */
       public void update_skills(){
               if(this.condition>this.previous_condition){
                       if(this.attack_precision<this.chosen_attack_precision){
                               this.attack_precision++;
                       }
                       if(this.pass_precision<this.chosen_pass_precision){
                               this.pass_precision++;
                       }
                       if(this.serve_precision<this.chosen_serve_precision){
                               this.serve_precision++;
                       }
               }
               if(this.condition<this.previous_condition){
                       if(this.attack_precision>0){
                               this.attack_precision--;
                       }
                       if(this.pass_precision>0){
                               this.pass_precision--;
                       }
                       if(this.serve_precision>0){
                               this.serve_precision--;
                       }
               }
       }

       @Override
       public void update() {
               try {
                       if( position.distance(movementTarget) > 1 ) {
                               movement = new MKVector(movementTarget).sub(position).normalise().scale(fspeed);
                               position.add(movement);

                               if(this.fspeed >=0.25f) { // the more player walks the lower is the speed
                                       this.fspeed -= 0.0002f;
                               }
                       }
                       else {  // if player do not any move
                               if(this.fspeed <= this.chosen_speed) {
                                       this.fspeed += 0.00005f; // speed rises
                               }
                               if(this.condition<100) {
                               this.condition += 0.001f;  // condition rises
                               }
                               if(((int)this.condition%10==0 && (int)this.previous_condition%10==9) || ((int)this.condition%10==5 && (int)this.previous_condition%10==4) ) { // condition which will be used to improve players precision

                                       if(this.attack_precision<this.chosen_attack_precision)
	                                   this.attack_precision++;
                                       if(this.pass_precision<this.chosen_pass_precision)
                                       this.pass_precision++;
                                       if(this.serve_precision<this.chosen_serve_precision)
                                       this.serve_precision++;
                                       if(this.fpower<this.chosen_power)
                                       this.fpower += 0.05f;
                                       
                               }
                       }

                       this.previous_condition = this.condition;

               }catch(NullPointerException ex) {

               }
       }
}